package com.cryptoneedle.garden.api;


import cn.hutool.v7.core.bean.BeanUtil;
import cn.hutool.v7.core.tree.MapTree;
import com.bubbles.engine.common.core.result.Result;
import com.cryptoneedle.garden.dto.SourceCatalogDto;
import com.cryptoneedle.garden.entity.source.enhance.SourceDimension;
import com.cryptoneedle.garden.entity.source.metadata.SourceCatalog;
import com.cryptoneedle.garden.entity.source.metadata.SourceColumn;
import com.cryptoneedle.garden.entity.source.metadata.SourceDatabase;
import com.cryptoneedle.garden.entity.source.metadata.SourceTable;
import com.cryptoneedle.garden.service.crud.garden.source.*;
import com.cryptoneedle.garden.service.garden.source.ConnectionService;
import com.cryptoneedle.garden.service.garden.source.ScriptService;
import com.cryptoneedle.garden.service.garden.source.SourceSyncService;
import com.cryptoneedle.garden.service.seatunnel.SeatunnelService;
import com.cryptoneedle.garden.vo.CatalogSaveVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * <p>description: 数据源中心控制器 - 提供数据源管理、元数据同步、脚本生成等功能 </p>
 *
 * @author CryptoNeedle
 * @date 2025-10-29
 */
@Tag(name = "数据源中心", description = "数据源管理、元数据同步、脚本生成相关接口")
@RestController
@RequestMapping("/data-source")
public class DataSourceController {

    @Autowired
    private FoundSourceService select;
    @Autowired
    private AddSourceService add;
    @Autowired
    private PatchSourceService patch;
    @Autowired
    private SaveSourceService save;
    @Autowired
    private DeleteSourceService delete;

    @Autowired
    private ConnectionService connectionService;
    @Autowired
    private SourceSyncService sourceSyncService;
    @Autowired
    private ScriptService scriptService;
    @Autowired
    private SeatunnelService seatunnelService;

    // ===================== 数据源查询相关接口 =====================

    @PostMapping("/tree")
    @Operation(summary = "获取数据源树形结构", description = "获取数据源的层级树形结构，支持选择性显示服务器和表节点")
    public Result<List<MapTree<Object>>> tree(
            @Parameter(description = "是否显示服务器节点") @RequestParam("displayServer") Boolean displayServer,
            @Parameter(description = "是否显示表节点") @RequestParam("displayTable") Boolean displayTable) {
        return Result.success(select.tree(displayServer, displayTable));
    }

    @PostMapping("/catalogs")
    @Operation(summary = "获取所有数据源列表", description = "获取系统中所有配置的数据源目录列表")
    public Result<List<SourceCatalogDto>> listCatalog() {
        return Result.success(BeanUtil.copyToList(select.catalogs(), SourceCatalogDto.class));
    }

    @PostMapping("/catalog/{catalogName}")
    @Operation(summary = "获取指定数据源详情", description = "根据目录名称获取数据源详细信息")
    public Result<SourceCatalogDto> getCatalog(@Parameter(description = "数据源目录名称") @PathVariable String catalogName) {
        return Result.success(BeanUtil.copyProperties(select.catalog(catalogName), SourceCatalogDto.class));
    }

    @PostMapping("/catalog/{catalogName}/databases")
    @Operation(summary = "获取数据源下的数据库列表", description = "获取指定数据源下的所有数据库列表")
    public Result<List<SourceDatabase>> listDatabase(@Parameter(description = "数据源目录名称") @PathVariable String catalogName) {
        return Result.success(select.databases(catalogName));
    }

    @PostMapping("/catalog/{catalogName}/databases/enabled")
    @Operation(summary = "获取数据源下的启用数据库列表", description = "获取指定数据源下的所有启用状态数据库列表")
    public Result<List<SourceDatabase>> listEnabledDatabases(@Parameter(description = "数据源目录名称") @PathVariable String catalogName) {
        return Result.success(select.databasesEnabled(catalogName));
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}")
    @Operation(summary = "获取指定数据库详情", description = "根据目录名称和数据库名称获取数据库详细信息")
    public Result<SourceDatabase> getDatabase(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName) {
        return Result.success(select.database(catalogName, databaseName));
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/tables")
    @Operation(summary = "获取数据库下的表列表", description = "获取指定数据库下的所有表列表")
    public Result<List<SourceTable>> listTable(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName) {
        return Result.success(select.tables(catalogName, databaseName));
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/tables/enabled")
    @Operation(summary = "获取数据库下的启用表列表", description = "获取指定数据库下的所有启用状态表列表")
    public Result<List<SourceTable>> listEnabledTable(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName) {
        return Result.success(select.tablesEnabled(catalogName, databaseName));
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/table/{tableName}")
    @Operation(summary = "获取指定表详情", description = "根据完整路径获取表的详细信息")
    public Result<SourceTable> getTable(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "表名称") @PathVariable String tableName) {
        return Result.success(select.table(catalogName, databaseName, tableName));
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/table/{tableName}/columns")
    @Operation(summary = "获取表的列信息", description = "获取指定表的所有列详细信息")
    public Result<List<SourceColumn>> listColumn(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "表名称") @PathVariable String tableName) {
        return Result.success(select.columns(catalogName, databaseName, tableName));
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/table/{tableName}/dimensions")
    @Operation(summary = "获取表的维度列信息", description = "获取指定表的维度列信息（用于Doris UNIQUE KEY）")
    public Result<List<SourceDimension>> listDimension(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "表名称") @PathVariable String tableName) {
        return Result.success(select.dimensions(catalogName, databaseName, tableName));
    }

    // ===================== 连接测试相关接口 =====================

    @PostMapping("/catalog/test/server")
    @Operation(summary = "测试服务器连接", description = "测试SSH连接或直连的服务器连通性")
    public Result<Boolean> testServer(@RequestBody CatalogSaveVo vo) {
        return Result.success(connectionService.testServer(vo.createCatalog()));
    }

    @PostMapping("/catalog/test/jdbc")
    @Operation(summary = "测试JDBC连接", description = "测试数据库JDBC连接的有效性")
    public Result<Boolean> testJdbc(@RequestBody CatalogSaveVo vo) {
        return Result.success(connectionService.testJdbc(vo.createCatalog()));
    }

    @PostMapping("/catalog/test/doris")
    @Operation(summary = "测试Doris连接", description = "测试目标Doris数据仓库的连接有效性")
    public Result<Boolean> testDoris(@RequestBody CatalogSaveVo vo) {
        return Result.success(connectionService.testDoris(vo.createCatalog()));
    }

    @PostMapping("/catalog/{catalogName}/test/server")
    @Operation(summary = "测试数据源服务器连接", description = "测试SSH连接或直连的服务器连通性")
    public Result<Boolean> testCatalogServer(@Parameter(description = "数据源目录名称") @PathVariable String catalogName) {
        return Result.success(connectionService.testServer(select.catalog(catalogName)));
    }

    @PostMapping("/catalog/{catalogName}/test/jdbc")
    @Operation(summary = "测试数据源测试JDBC连接", description = "测试数据库JDBC连接的有效性")
    public Result<Boolean> testCatalogJdbc(@Parameter(description = "数据源目录名称") @PathVariable String catalogName) {
        return Result.success(connectionService.testJdbc(select.catalog(catalogName)));
    }

    @PostMapping("/catalog/{catalogName}/test/doris")
    @Operation(summary = "测试数据源Doris连接", description = "测试目标Doris数据仓库的连接有效性")
    public Result<Boolean> testCatalogDoris(@Parameter(description = "数据源目录名称") @PathVariable String catalogName) {
        return Result.success(connectionService.testDoris(select.catalog(catalogName)));
    }

    // ===================== 数据源管理相关接口 =====================

    @PostMapping("/catalog/add") // 完成
    @Operation(summary = "添加数据源目录", description = "添加新的数据源目录配置，包括连接信息和Doris配置")
    public Result<Void> addCatalog(@Validated @RequestBody CatalogSaveVo vo) {
        add.add(vo);
        return Result.success();
    }

    @PostMapping("/catalog/save") // 完成
    @Operation(summary = "更新数据源目录", description = "更新现有数据源目录配置")
    public Result<Void> saveCatalog(@Validated @RequestBody CatalogSaveVo vo) {
        save.save(vo);
        return Result.success();
    }

    // ===================== 同步管理相关接口 =====================

    @PostMapping("/catalog/{catalogName}/sync")
    @Operation(summary = "同步指定数据源", description = "同步指定数据源的所有元数据")
    public Result<Void> syncCatalog(@Parameter(description = "数据源目录名称") @PathVariable String catalogName) {
        SourceCatalog catalog = select.catalog(catalogName);
        sourceSyncService.syncCatalog(catalog);
        return Result.success();
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/sync")
    @Operation(summary = "同步指定数据库", description = "同步指定数据源下的特定数据库元数据")
    public Result<Void> syncDatabase(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName) {
        sourceSyncService.syncDatabase(catalogName, databaseName);
        return Result.success();
    }

    // ===================== 状态管理相关接口 =====================

    @PostMapping("/catalog/{catalogName}/enabled")
    @Operation(summary = "启用/禁用数据源", description = "设置数据源的启用状态")
    public Result<Void> setCatalogEnabled(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "启用状态") @RequestParam Boolean enabled) {
        patch.catalogEnabled(catalogName, enabled);
        return Result.success();
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/enabled")
    @Operation(summary = "启用/禁用数据库", description = "设置数据库的启用状态")
    public Result<Void> setDatabaseEnabled(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "启用状态") @RequestParam Boolean enabled) {
        patch.databaseEnabled(catalogName, databaseName, enabled);
        return Result.success();
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/table/{tableName}/enabled")
    @Operation(summary = "启用/禁用表", description = "设置表的启用状态")
    public Result<Void> setTableEnabled(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "表名称") @PathVariable String tableName,
            @Parameter(description = "启用状态") @RequestParam Boolean enabled) {
        patch.tableEnabled(catalogName, databaseName, tableName, enabled);
        return Result.success();
    }

    @PostMapping("/catalog/{catalogName}/systemCode")
    @Operation(summary = "更新数据源系统编码", description = "更新数据源的默认系统编码，会级联更新下级数据库")
    public Result<Void> setCatalogSystemCode(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "系统编码") @RequestParam String systemCode) {
        patch.catalogDefaultSystemCode(catalogName, systemCode);
        return Result.success();
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/systemCode")
    @Operation(summary = "更新数据库系统编码", description = "更新数据库的默认系统编码，会级联更新下级表")
    public Result<Void> setDatabaseSystemCode(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "系统编码") @RequestParam String systemCode) {
        patch.databaseDefaultSystemCode(catalogName, databaseName, systemCode);
        return Result.success();
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/table/{tableName}/systemCode")
    @Operation(summary = "更新表系统编码", description = "更新表的系统编码")
    public Result<Void> setTableSystemCode(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "表名称") @PathVariable String tableName,
            @Parameter(description = "系统编码") @RequestParam String systemCode) {
        patch.tableSystemCode(catalogName, databaseName, tableName, systemCode);
        return Result.success();
    }

    // ===================== 脚本生成相关接口 =====================

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/table/{tableName}/script/doris")
    @Operation(summary = "生成Doris完整迁移脚本", description = "生成包含CREATE CATALOG、CREATE TABLE、SELECT的完整Doris迁移脚本")
    public Result<String> generateDorisScript(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "表名称") @PathVariable String tableName) {
        return Result.success(scriptService.dorisScript(catalogName, databaseName, tableName));
    }

    @PostMapping("/catalog/{catalogName}/database/{databaseName}/table/{tableName}/script/seatunnel")
    @Operation(summary = "生成Seatunnel脚本", description = "生成Seatunnel迁移脚本")
    public Result<String> generateSeatunnelScript(
            @Parameter(description = "数据源目录名称") @PathVariable String catalogName,
            @Parameter(description = "数据库名称") @PathVariable String databaseName,
            @Parameter(description = "表名称") @PathVariable String tableName) {
        return Result.success(seatunnelService.seatunnelScript(catalogName, databaseName, tableName));
    }
}